package comm

import (
	"gitee.com/gcom/gbox/errors"
	"github.com/PuerkitoBio/goquery"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	proxyIps  []string
	timestamp = DefaultDateTime
	lock      sync.RWMutex
)

func GetPoolIps() []string {
	proxyIps = proxyIps[:0]
	if time.Now().Sub(timestamp) >= time.Hour {
		list := make([]string, 0, 30)
		sem := make(chan struct{}, 100) // 测试代理IP有效性并发量为100
		defer close(sem)
		var tg sync.WaitGroup
		for i := 1; i <= 100 && len(list) < 30; i++ {
			tg.Add(1)
			go getProxyIp(i, sem, tg)
			time.Sleep(2 * time.Second)
		}
		tg.Wait()
		timestamp = time.Now()
	}
	return proxyIps
}

func getProxyIp(page int, sem chan struct{}, tg sync.WaitGroup) ([]string, error) {
	defer tg.Done()
	var client = &http.Client{Timeout: 30 * time.Second}
	req, _ := http.NewRequest("GET", "http://www.xicidaili.com/wt/"+strconv.Itoa(page), nil)
	resp, err := client.Do(req)
	if err != nil {
		Log.Errorf("下载股票列表失败%v", err)
		return nil, err
	}
	defer resp.Body.Close()

	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		log.Printf("更新代理IP池失败：%v", err)
		return nil, errors.Wrap(err, "更新代理IP池失败")
	}

	nodes := doc.Find("#ip_list > tbody > tr")
	log.Printf("获取代理IP %d 条，第%d页", nodes.Size(), page)
	ips := make([]string, nodes.Size())
	var wg sync.WaitGroup
	nodes.Each(func(i int, context *goquery.Selection) {
		if i == 0 {
			return
		}
		ip := context.Find("td").Eq(1).Text()
		port := context.Find("td").Eq(2).Text()
		httpType := context.Find("td").Eq(5).Text()
		proxy := strings.ToLower(httpType) + "://" + ip + ":" + port
		// nim := context.Find("td").Eq(4).Text() //是否是高匿,高匿的可以隐藏你的原始IP

		if ip != "" && port != "" {
			wg.Add(1)
			go func(ip string, index int) {
				sem <- struct{}{}
				defer func() {
					wg.Done()
					<-sem
				}()

				req, _ := http.NewRequest("GET", "http://h.fantacya.org/p", nil)
				proxyUrl, _ := url.Parse(proxy)
				client := &http.Client{
					Timeout:   time.Second,
					Transport: &http.Transport{Proxy: http.ProxyURL(proxyUrl)},
				}
				resp, _ := client.Do(req)
				defer resp.Body.Close()

				if resp != nil && resp.StatusCode == 200 {
					buf := make([]byte, 1024)
					n, _ := resp.Body.Read(buf)
					body := string(buf[:n])
					if body == "OK" {
						log.Printf("验证代理通过: %s", proxy)
						ips[i] = proxy
						return
					}
				}
				// log.Printf("验证代理失败: %s", proxy)
			}(proxy, i)
		}
		time.Sleep(time.Second)
	})

	wg.Wait()
	var list []string
	for _, proxy := range ips {
		if proxy != "" {
			log.Printf("==> 验证通过代理: %s", proxy)
			list = append(list, proxy)
		}
	}
	lock.Lock()
	defer lock.Unlock()
	proxyIps = append(proxyIps, list...)
	return list, nil
}
